1 module unde.games.dizzy.omega.rope; 2 3 import derelict.opengl3.gl; 4 5 import std.algorithm; 6 import std.conv; 7 import std.math; 8 import std.stdio; 9 import unde.games.object; 10 import unde.games.renderer; 11 import unde.games.collision_detector; 12 import unde.games.object; 13 import unde.global_state; 14 15 class Rope:StaticGameObject 16 { 17 float by, segl; 18 float[3][] rope; 19 20 static int num; 21 static GLuint rope_texture; 22 int number; 23 int static_segments; 24 25 int cut_segm = -1; 26 27 this(MainGameObject root, float[3] rope_start, float[3] rope_end, float by, uint length, float segl, 28 int static_segments = 1) 29 { 30 x = rope_end[0]; 31 y = rope_end[1]; 32 z = rope_end[2]; 33 34 this.by = by; 35 this.segl = segl; 36 if (length > 1) 37 { 38 float rx = rope_start[0]; 39 float ry = rope_start[1]; 40 float rz = rope_start[2]; 41 if (static_segments == 1) 42 { 43 foreach (i; 0..length) 44 { 45 rope ~= [rx + (x-rx)*i/(length-1), 46 ry + (y-ry)*i/(length-1), 47 rz + (z-rz)*i/(length-1)]; 48 } 49 } 50 else 51 { 52 foreach (i; 0..static_segments) 53 { 54 rope ~= [rx + (x-rx)*i/(static_segments-1), 55 ry + (y-ry)*i/(static_segments-1), 56 rz + (z-rz)*i/(static_segments-1)]; 57 } 58 59 foreach (i; static_segments..length) 60 { 61 rope ~= [x, y, z]; 62 } 63 64 cut_segm = length - 1; 65 } 66 } 67 68 this.static_segments = static_segments; 69 70 if (num == 0) 71 { 72 rope_texture = load_texture("models/dizzy/rope.png"); 73 } 74 number = num++; 75 76 super(root); 77 } 78 79 void reinit() 80 { 81 if (rope.length > 1) 82 { 83 float rx = rope[0][0]; 84 float ry = rope[0][1]; 85 float rz = rope[0][2]; 86 87 if (static_segments == 1) 88 { 89 foreach (i; 0..rope.length) 90 { 91 rope[i] = [rx + (x-rx)*i/(rope.length-1), 92 ry + (y-ry)*i/(rope.length-1), 93 rz + (z-rz)*i/(rope.length-1)]; 94 } 95 } 96 else 97 { 98 foreach (i; 0..static_segments) 99 { 100 rope [i] = [rx + (x-rx)*i/(static_segments-1), 101 ry + (y-ry)*i/(static_segments-1), 102 rz + (z-rz)*i/(static_segments-1)]; 103 } 104 105 foreach (i; static_segments..rope.length) 106 { 107 rope[i] = [x, y, z]; 108 } 109 110 cut_segm = cast(int) rope.length - 1; 111 } 112 } 113 } 114 115 float length(float[3] v) 116 { 117 return sqrt(v[0]^^2 + v[1]^^2 + v[2]^^2); 118 } 119 120 void normalize(ref float[3] v) 121 { 122 float len = length(v); 123 v[] /= len; 124 } 125 126 float[3] produce(float[3] v1, float[3] v2) 127 { 128 return [ v1[2]*v2[1] - v1[1]*v2[2], v1[0]*v2[2] - v1[2]*v2[0], v1[1]*v2[0] - v1[0]*v2[1] ]; 129 } 130 131 void cut(int segm) 132 { 133 cut_segm = segm; 134 } 135 136 override void draw(GlobalState gs) 137 { 138 draw_part(gs, 0, rope.length - 1); 139 } 140 141 void draw_part(GlobalState gs, size_t a, size_t b) 142 { 143 if (rope.length < 2) return; 144 145 glEnable(GL_LIGHTING); 146 glDisable(GL_COLOR_MATERIAL); 147 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [0.8f, 0.8f, 0.8f, 1.0f].ptr); 148 glBindTexture(GL_TEXTURE_2D, rope_texture); 149 150 foreach(i; a..b) 151 { 152 if (i == cut_segm) continue; 153 154 float[3] rs0 = (i>0 ? rope[i-1] : rope[i]); 155 float[3] rs1 = rope[i]; 156 float[3] rs2 = rope[i+1]; 157 float[3] rs3 = (i<rope.length-2 ? rope[i+2] : rope[i+1]); 158 159 float[3] rs10 = rs0[] - rs1[]; 160 float[3] rs12 = rs2[] - rs1[]; 161 if (length(rs10) < 0.001) rs10[] = -rs12[]; 162 normalize(rs10); 163 normalize(rs12); 164 165 float[3] v10, v11, v12, v13; 166 167 float[3] rs10m12 = rs10[] - rs12[]; 168 float[3] rs10p12 = rs10[] + rs12[]; 169 if (length(rs10m12) < 0.001 || length(rs10p12) < 0.001) 170 { 171 //ax+by+cz = 0 172 if (abs(rs12[0]) > 0.01 && abs(rs12[1]) > 0.01 && abs(rs12[2]) > 0.01) 173 { 174 v10 = [-rs12[1]/rs12[0], 1.0, 0.0]; 175 v11 = [-rs12[2]/rs12[0], 0.0, 1.0]; 176 normalize(v10); 177 normalize(v11); 178 } 179 else if (abs(rs12[0]) > 0.01 && abs(rs12[1]) > 0.01) 180 { 181 v10 = [-rs12[1]/rs12[0], 1.0, 0.0]; 182 v11 = [0.0, 0.0, 1.0]; 183 normalize(v10); 184 } 185 else if (abs(rs12[0]) > 0.01 && abs(rs12[2]) > 0.01) 186 { 187 v10 = [-rs12[2]/rs12[0], 0.0, 1.0]; 188 v11 = [0.0, 1.0, 0.0]; 189 normalize(v10); 190 } 191 else if (abs(rs12[1]) > 0.01 && abs(rs12[2]) > 0.01) 192 { 193 v10 = [1.0, 0.0, 0.0]; 194 v11 = [0.0, 1.0, -rs12[1]/rs12[2]]; 195 normalize(v11); 196 } 197 else if (abs(rs12[0]) > 0.01) 198 { 199 v10 = [0.0, 1.0, 0.0]; 200 v11 = [0.0, 0.0, 1.0]; 201 } 202 else if (abs(rs12[1]) > 0.01) 203 { 204 v10 = [1.0, 0.0, 0.0]; 205 v11 = [0.0, 0.0, 1.0]; 206 } 207 else if (abs(rs12[2]) > 0.01) 208 { 209 v10 = [0.0, 1.0, 0.0]; 210 v11 = [1.0, 0.0, 0.0]; 211 } 212 } 213 else 214 { 215 v10 = rs10p12; 216 v11 = produce(rs10, rs12); 217 normalize(v10); 218 normalize(v11); 219 } 220 221 v12[] = -v10[]; 222 v13[] = -v11[]; 223 224 float[3] rs21 = rs1[] - rs2[]; 225 float[3] rs23 = rs3[] - rs2[]; 226 if (length(rs23) < 0.001) rs23[] = -rs21[]; 227 normalize(rs21); 228 normalize(rs23); 229 230 float[3] v20, v21, v22, v23; 231 232 float[3] rs21m23 = rs21[] - rs23[]; 233 float[3] rs21p23 = rs21[] + rs23[]; 234 if (length(rs21m23) < 0.001 || length(rs21p23) < 0.001) 235 { 236 //ax+by+cz = 0 237 if (abs(rs21[0]) > 0.01 && abs(rs21[1]) > 0.01 && abs(rs21[2]) > 0.01) 238 { 239 v20 = [-rs21[1]/rs21[0], 1.0, 0.0]; 240 v21 = [-rs21[2]/rs21[0], 0.0, 1.0]; 241 normalize(v20); 242 normalize(v21); 243 } 244 else if (abs(rs21[0]) > 0.01 && abs(rs21[1]) > 0.01) 245 { 246 v20 = [-rs21[1]/rs21[0], 1.0, 0.0]; 247 v21 = [0.0, 0.0, 1.0]; 248 normalize(v20); 249 } 250 else if (abs(rs21[0]) > 0.01 && abs(rs21[2]) > 0.01) 251 { 252 v20 = [-rs21[2]/rs21[0], 0.0, 1.0]; 253 v21 = [0.0, 1.0, 0.0]; 254 normalize(v20); 255 } 256 else if (abs(rs21[1]) > 0.01 && abs(rs21[2]) > 0.01) 257 { 258 v20 = [1.0, 0.0, 0.0]; 259 v21 = [0.0, 1.0, -rs21[1]/rs21[2]]; 260 normalize(v21); 261 } 262 else if (abs(rs21[0]) > 0.01) 263 { 264 v20 = [0.0, 1.0, 0.0]; 265 v21 = [0.0, 0.0, 1.0]; 266 } 267 else if (abs(rs21[1]) > 0.01) 268 { 269 v20 = [1.0, 0.0, 0.0]; 270 v21 = [0.0, 0.0, 1.0]; 271 } 272 else if (abs(rs21[2]) > 0.01) 273 { 274 v20 = [0.0, 1.0, 0.0]; 275 v21 = [1.0, 0.0, 0.0]; 276 } 277 } 278 else 279 { 280 v20 = rs21p23; 281 v21 = produce(rs21, rs23); 282 normalize(v20); 283 normalize(v21); 284 } 285 286 v22[] = -v20[]; 287 v23[] = -v21[]; 288 289 v10[] /= 8; 290 v11[] /= 8; 291 v12[] /= 8; 292 v13[] /= 8; 293 v20[] /= 8; 294 v21[] /= 8; 295 v22[] /= 8; 296 v23[] /= 8; 297 298 float[3] r10 = v10[] + rs1[]; 299 float[3] r11 = v11[] + rs1[]; 300 float[3] r12 = v12[] + rs1[]; 301 float[3] r13 = v13[] + rs1[]; 302 303 float[3] r20 = v20[] + rs2[]; 304 float[3] r21 = v21[] + rs2[]; 305 float[3] r22 = v22[] + rs2[]; 306 float[3] r23 = v23[] + rs2[]; 307 308 float tx1 = 1.0*i/(rope.length-1); 309 float tx2 = 1.0*(i+1)/(rope.length-1); 310 311 glBegin(GL_POLYGON); 312 glTexCoord2f(tx1, 0.0); 313 glNormal3fv(v10.ptr); 314 glVertex3fv(r10.ptr); 315 316 glTexCoord2f(tx2, 0.0); 317 glNormal3fv(v20.ptr); 318 glVertex3fv(r20.ptr); 319 320 glTexCoord2f(tx2, 0.25); 321 glNormal3fv(v21.ptr); 322 glVertex3fv(r21.ptr); 323 324 glTexCoord2f(tx1, 0.25); 325 glNormal3fv(v11.ptr); 326 glVertex3fv(r11.ptr); 327 glEnd(); 328 329 glBegin(GL_POLYGON); 330 glTexCoord2f(tx1, 0.25); 331 glNormal3fv(v11.ptr); 332 glVertex3fv(r11.ptr); 333 334 glTexCoord2f(tx2, 0.25); 335 glNormal3fv(v21.ptr); 336 glVertex3fv(r21.ptr); 337 338 glTexCoord2f(tx2, 0.50); 339 glNormal3fv(v22.ptr); 340 glVertex3fv(r22.ptr); 341 342 glTexCoord2f(tx1, 0.50); 343 glNormal3fv(v12.ptr); 344 glVertex3fv(r12.ptr); 345 glEnd(); 346 347 glBegin(GL_POLYGON); 348 glTexCoord2f(tx1, 0.50); 349 glNormal3fv(v12.ptr); 350 glVertex3fv(r12.ptr); 351 352 glTexCoord2f(tx2, 0.50); 353 glNormal3fv(v22.ptr); 354 glVertex3fv(r22.ptr); 355 356 glTexCoord2f(tx2, 0.75); 357 glNormal3fv(v23.ptr); 358 glVertex3fv(r23.ptr); 359 360 glTexCoord2f(tx1, 0.75); 361 glNormal3fv(v13.ptr); 362 glVertex3fv(r13.ptr); 363 glEnd(); 364 365 glBegin(GL_POLYGON); 366 glTexCoord2f(tx1, 0.75); 367 glNormal3fv(v13.ptr); 368 glVertex3fv(r13.ptr); 369 370 glTexCoord2f(tx2, 0.75); 371 glNormal3fv(v23.ptr); 372 glVertex3fv(r23.ptr); 373 374 glTexCoord2f(tx2, 1.00); 375 glNormal3fv(v20.ptr); 376 glVertex3fv(r20.ptr); 377 378 glTexCoord2f(tx1, 1.00); 379 glNormal3fv(v10.ptr); 380 glVertex3fv(r10.ptr); 381 glEnd(); 382 } 383 } 384 385 override bool tick(GlobalState gs) 386 { 387 if (rope.length > 1) 388 { 389 for (size_t i = rope.length-2; i >= static_segments; i--) 390 { 391 float[3] r1 = rope[i+1]; 392 float[3] r2 = rope[i]; 393 float[3] r3 = rope[i-1]; 394 395 if (i == cut_segm) 396 r1 = rope[i]; 397 else if (i+1 == cut_segm) 398 r3 = rope[i]; 399 400 bool moved; 401 float[3] l12 = r1[] - r2[]; 402 float[3] l23 = r3[] - r2[]; 403 404 if (length(l12) > segl || length(l23) > segl) 405 { 406 if (cut_segm >= 0) 407 { 408 float[3] l13 = r1[] - r3[]; 409 float len = length(l13); 410 411 if (i <= cut_segm) 412 { 413 if (r1[1] < r3[1]) 414 { 415 rope[i][] = r1[]*segl/len + r3[]*(len-segl)/len; 416 moved = true; 417 } 418 } 419 else 420 { 421 if (r3[1] < r1[1]) 422 { 423 rope[i][] = r1[]*(len-segl)/len + r3[]*segl/len; 424 moved = true; 425 } 426 } 427 } 428 else 429 { 430 rope[i][] = (r1[] + r3[])/2; 431 moved = true; 432 } 433 } 434 435 if (!moved && rope[i][1] > by) 436 { 437 rope[i][1] -= 0.1; 438 439 r2 = rope[i]; 440 l12[] = r1[] - r2[]; 441 l23[] = r3[] - r2[]; 442 443 if (cut_segm < 0) 444 { 445 if (length(l12) > segl || length(l23) > segl) 446 { 447 float dy; 448 449 if ( length(l12) > length(l23) ) 450 dy = sqrt(segl^^2 - l12[0]^^2 - l12[2]^^2) - l12[1]; 451 else 452 dy = sqrt(segl^^2 - l23[0]^^2 - l23[2]^^2) - l23[1]; 453 454 rope[i][1] -= dy; 455 } 456 } 457 else 458 { 459 if (i <= cut_segm) 460 { 461 if (length(l23) > segl) 462 rope[i][1] -= sqrt(segl^^2 - l23[0]^^2 - l23[2]^^2) - l23[1]; 463 } 464 else 465 { 466 if (length(l12) > segl) 467 rope[i][1] -= sqrt(segl^^2 - l12[0]^^2 - l12[2]^^2) - l12[1]; 468 } 469 } 470 } 471 } 472 } 473 474 return true; 475 } 476 477 override void load(string[string] s) 478 { 479 string p = "rope"~number.to!(string); 480 if (p~"-cut" in s) 481 cut_segm = s[p~"-cut"].to!(int); 482 else 483 cut_segm = -1; 484 485 foreach(i; 0..10) 486 { 487 tick(null); 488 } 489 } 490 491 override void save(ref string[string] s) 492 { 493 string p = "rope"~number.to!(string); 494 if (cut_segm >= 0) 495 s[p~"-cut"] = cut_segm.to!(string); 496 } 497 } 498